﻿/*
*      
*          ┌─┐       ┌─┐
*       ┌──┘ ┴───────┘ ┴──┐
*       │                 │
*       │       ───       │
*       │  ─┬┘       └┬─  │
*       │                 │
*       │       ─┴─       │
*       │                 │
*       └───┐         ┌───┘
*           │         │
*           │         │
*           │         │
*           │         └──────────────┐
*           │                        │
*           │                        ├─┐
*           │                        ┌─┘    
*           │                        │
*           └─┐  ┐  ┌───────┬──┐  ┌──┘         
*             │ ─┤ ─┤       │ ─┤ ─┤         
*             └──┴──┘       └──┴──┘ 
*                 神兽保佑 
*                 代码无BUG! 
*  Author shang
*  2022-07-21 17:53:00
*/

using Autofac.Annotation;
using Quartz;
using Quartz.Impl.Matchers;
using Quartz.Impl.Triggers;
using SqlSugar;
using TS.Common;
using TS.Common.Db;
using TS.Model;

namespace TS.Services;

[Component(AutofacScope = AutofacScope.InstancePerLifetimeScope)]
public class TaskService : DbContext
{
    [Autowired] public QuartzService _QuartzService { get; set; }

    /// <summary>
    /// 任务列表
    /// </summary>
    /// <param name="search"></param>
    /// <returns></returns>
    public async Task<HttpResult> GeList(TaskSearchModel search)
    {
        HttpResult res = new HttpResult();
        RefAsync<int> totalNumber = 0;
        var list = await Db.Queryable<TaskOptions>()
            .WhereIF(!string.IsNullOrEmpty(search.taskname), x => x.TaskName.Contains(search.taskname))
            .ToPageListAsync(search.PageIndex, search.PageSize, totalNumber);
        PageList page = new PageList(totalNumber, list);
        res.data = page;
        return res;
    }


    /// <summary>
    /// 新增删除任务
    /// </summary>
    /// <param name="task"></param>
    /// <returns></returns>
    public async Task<HttpResult> AddOrUpdateTask(TaskOptions task)
    {
        HttpResult res = new HttpResult();
        var count = 0;
        DateTime datetime = DateTime.Now;
        (bool, string) validExpression = task.Interval.IsValidExpression();
        if (!validExpression.Item1)
        {
            res.code = 1;
            res.msg = validExpression.Item2;
            return res;
        }


        ///新增
        if (task.ID == 0)
        {
            var data = await Db.Queryable<TaskOptions>()
                .Where(x => x.TaskName == task.TaskName && x.GroupName == task.GroupName).FirstAsync();
            if (data != null)
            {
                res.code = 1;
                res.msg = "任务名已存在";
                return res;
            }

            count = await Db.Insertable(task).ExecuteReturnIdentityAsync();
            var scheduler = await _QuartzService.CreateQuartzTask(task);
            // await scheduler.Start();
        }
        else
        {
            var data = await Db.Queryable<TaskOptions>()
                .Where(x => x.TaskName == task.TaskName && x.ID != task.ID && x.GroupName == task.GroupName)
                .FirstAsync();
            if (data != null)
            {
                res.code = 1;
                res.msg = "任务名已存在";
                return res;
            }

            count = await Db.Updateable(task).IgnoreColumns(x => new { x.LastRunTime }).ExecuteCommandAsync();
            res = await _QuartzService.Update(task);
        }

        if (count == 0)
        {
            res.code = 1;
            res.msg = "新增修改失败!";
        }

        return res;
    }

    /// <summary>
    /// 删除任务
    /// </summary>
    /// <param name="ids"></param>
    /// <returns></returns>
    public async Task<HttpResult> Delete(List<int> ids)
    {
        HttpResult res = new HttpResult();
        var dbdata = await Db.Queryable<TaskOptions>().Where(x => ids.Contains(x.ID)).ToListAsync();
        var count = await Db.Deleteable<TaskOptions>().Where(x => ids.Contains(x.ID)).ExecuteCommandAsync();
        foreach (var item in dbdata)
        {
            await _QuartzService.Remove(item);
        }

        if (count == 0)
        {
            res.code = 1;
            res.msg = "删除失败";
        }

        return res;
    }

    /// <summary>
    /// 暂停任务
    /// </summary>
    /// <param name="ids"></param>
    /// <returns></returns>
    public async Task<HttpResult> pauseTask(List<int> ids)
    {
        HttpResult res = new HttpResult();
        var dbdata = await Db.Queryable<TaskOptions>().Where(x => ids.Contains(x.ID)).ToListAsync();
        var count = await Db.Updateable<TaskOptions>().SetColumns(x => new TaskOptions() { Status = 1 })
            .Where(x => ids.Contains(x.ID)).ExecuteCommandAsync();

        foreach (var item in dbdata)
        {
            await _QuartzService.Pause(item);
        }

        if (count == 0)
        {
            res.code = 1;
            res.msg = "暂停失败";
        }

        return res;
    }

    /// <summary>
    /// 开始任务
    /// </summary>
    /// <param name="ids"></param>
    /// <returns></returns>
    public async Task<HttpResult> startTask(List<int> ids)
    {
        HttpResult res = new HttpResult();
        var dbdata = await Db.Queryable<TaskOptions>().Where(x => ids.Contains(x.ID)).ToListAsync();
        var count = await Db.Updateable<TaskOptions>().SetColumns(x => new TaskOptions() { Status = 0 })
            .Where(x => ids.Contains(x.ID)).ExecuteCommandAsync();
        foreach (var item in dbdata)
        {
            await _QuartzService.Start(item);
        }

        if (count == 0)
        {
            res.code = 1;
            res.msg = "暂停失败";
        }

        return res;
    }

    /// <summary>
    /// 执行任务
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<HttpResult> executeTask(int id)
    {
        HttpResult res = new HttpResult();
        var dbdata = await Db.Queryable<TaskOptions>().Where(x => x.ID == id).FirstAsync();
        res = await _QuartzService.Run(dbdata);
        return res;
    }


    /// <summary>
    /// 初始化所有任务
    /// </summary>
    public async Task InitJob()
    {
        var tasklist = await Db.Queryable<TaskOptions>().ToListAsync();
        var datetime = DateTime.Now;
        var scheduler = await _QuartzService.GetScheduler();
        await scheduler.Start();
        foreach (var item in tasklist)
        {
            await _QuartzService.CreateQuartzTask(item);
            if (item.Status == (int)TriggerState.Normal)
            {
            }
            else
            {
                List<JobKey> jobKeys = scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(item.GroupName)).Result
                    .ToList();

                JobKey jobKey = jobKeys.Where(s =>
                        scheduler.GetTriggersOfJob(s).Result.Any(x => (x as CronTriggerImpl).Name == item.TaskName))
                    .FirstOrDefault();

                var triggers = await scheduler.GetTriggersOfJob(jobKey);
                ITrigger trigger = triggers?.Where(x => (x as CronTriggerImpl).Name == item.TaskName).FirstOrDefault();
                await scheduler.PauseTrigger(trigger.Key);
                TaskLog log = new TaskLog()
                {
                    TaskID = item.ID,
                    group = item.GroupName,
                    taskname = item.TaskName,
                    BeginDate = datetime.ToString("yyyy-MM-dd HH:mm:ss:fff"),
                    Msg = $"作业:{item.TaskName},分组:{item.GroupName},新建时未启动原因,状态为:{item.Status}",
                };
                await Db.Insertable(log).ExecuteCommandAsync();
            }
        }
    }

    /// <summary>
    /// 获取执行的历史日志
    /// </summary>
    /// <param name="taskname"></param>
    /// <param name="groupname"></param>
    /// <param name="pageIndex"></param>
    /// <param name="pageSize"></param>
    /// <returns></returns>
    public async Task<HttpResult> getHis(string taskname, string groupname, int pageIndex = 1, int pageSize = 10)
    {
        HttpResult res = new HttpResult();
        RefAsync<int> totalNumber = 0;
        var list = await Db.Queryable<TaskLog>().Where(x => x.taskname == taskname && x.group == groupname)
            .ToPageListAsync(pageIndex, pageSize, totalNumber);
        PageList page = new PageList(totalNumber, list);
        res.data = page;
        return res;
    }
}